package com.tuzhi.convert.mq;


import cn.hutool.core.lang.UUID;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.tuzhi.common.domain.ResultBO;
import com.tuzhi.common.helper.ResultHelper;
import com.tuzhi.convert.dto.FilesModelDto;
import com.tuzhi.convert.dto.ProcessBoardRespiteDto;
import com.tuzhi.convert.httpclient.BillApi;
import com.tuzhi.convert.httpclient.FileStoreApi;
import com.tuzhi.convert.httpclient.ProcessApi;
import com.tuzhi.convert.utils.*;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;

import java.io.File;
import java.nio.file.Paths;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Callable;


/**
 * 转换任务
 */
public class MakeModelerTask implements Callable {
    Logger log = LoggerFactory.getLogger(MakeModelerTask.class);
    static final ObjectMapper MAPPER = new ObjectMapper();
    private ProcessBoardRespiteDto processBoardRespiteDto;

    private FilesModelDto filesModelDto;

    private Callback callback;

    private FileStoreApi fileStoreApi = SpringUtils.getBean(FileStoreApi.class);

    private ProcessApi processApi = SpringUtils.getBean(ProcessApi.class);

    private BillApi billApi = SpringUtils.getBean(BillApi.class);

    private CacheUtil cacheUtil = SpringUtils.getBean(CacheUtil.class);

    private String cadFilePath;
    private String stpFilePath;
    private String unRarZipFilePath;
    private String cacheFilePath;

    public MakeModelerTask(ProcessBoardRespiteDto processBoardRespiteDto, FileStoreApi fileStoreApi, String cadFilePath, String stpFilePath
            , String unRarZipFilePath, String cacheFilePath, Callback callback) {
        this.processBoardRespiteDto = processBoardRespiteDto;
        this.callback = callback;
        this.fileStoreApi = fileStoreApi;
        this.cadFilePath = cadFilePath;
        this.stpFilePath = stpFilePath;
        this.unRarZipFilePath = unRarZipFilePath;
        this.cacheFilePath = cacheFilePath;
    }

    public MakeModelerTask(ProcessBoardRespiteDto processBoardRespiteDto, String cadFilePath, String stpFilePath, String unRarZipFilePath, String cacheFilePath, Callback callback) {
        this.processBoardRespiteDto = processBoardRespiteDto;
        this.callback = callback;
        this.cadFilePath = cadFilePath;
        this.stpFilePath = stpFilePath;
        this.unRarZipFilePath = unRarZipFilePath;
        this.cacheFilePath = cacheFilePath;
    }

    @Override
    public Object call() throws Exception {
        Map dataMap = new HashMap();
        Map statMap = new HashMap();
        dataMap.put("data", statMap);
        ResultBO resultBO;
        File cadFile = null;
        //临时文件目录存放中间文件
        String terminalPath = cadFilePath + "\\" + UUID.randomUUID();
        String stpterminalPath = stpFilePath + "\\" + UUID.randomUUID();

        try {
            //新建临时文件
            File stpFileTemp = new File(stpterminalPath);
            if (!stpFileTemp.exists()) {
                stpFileTemp.mkdir();
            }
            log.info("当前线程名：：：{}，fileStoreApi={}", Thread.currentThread().getName(), fileStoreApi);

            //获取原模型信息
            filesModelDto = fileStoreApi.getReadyFile(processBoardRespiteDto.getModelId()).getData();

            String sourceFileName = StringUtils.isBlank(filesModelDto.getCadFileName()) ? filesModelDto.getStpFileName() : filesModelDto.getCadFileName();
            String fileType = CadFileTypeUtils.getCadFileTypeV2(sourceFileName);
            String fileName = String.format("%s.%s", filesModelDto.getId(), fileType);

            //判断文件是否在缓存中
            boolean useCache = false;
            if(cacheUtil.getCache(filesModelDto.getId().toString())){
                useCache = true;
            }

            boolean useOss = filesModelDto.isUseOss();//是否使用外部链接
            if (!useCache){
                //下载文件
                if (useOss) {
                    File terminalFile = new File(terminalPath);
                    if (!terminalFile.exists()) {
                        terminalFile.mkdirs();
                    }
                    cadFile = new OssUtil().downloadFile(filesModelDto.getCadFileUrl(), terminalPath + "\\" + fileName);
                    log.info("从外部下载模型源文件下载成功！");
                } else {//内部下载连接
                    String downLoadFilePath = StringUtils.isBlank(filesModelDto.getCadFileName()) ? filesModelDto.getFileUrl() : filesModelDto.getCadFileUrl();//需要判断原来是不是要转换的文件模型
                    cadFile = fileStoreApi.getCadFile(terminalPath, fileName, forestProgress -> {
                        System.out.println("total bytes: " + forestProgress.getTotalBytes());   // 文件大小
                        System.out.println("current bytes: " + forestProgress.getCurrentBytes());   // 已下载字节数
                        System.out.println("progress: " + Math.round(forestProgress.getRate() * 100) + "%");  // 已下载百分比
                        if (forestProgress.isDone()) {   // 是否下载完成
                            log.info("--------   Download Completed!   --------");
                        }
                    }, downLoadFilePath);
                }
                if (cadFile == null || !cadFile.exists()) {
                    return ResultHelper.error("下载模型文件失败，ModelId=" + filesModelDto.getId());
                }
                //缓存文件
                FileUtils.copyFile(cadFile,new File(cacheFilePath+"\\"+fileName));
                //写入缓存
                cacheUtil.setCache(filesModelDto.getId().toString(),new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
            }else{
                cadFile = new File(cacheFilePath+"\\"+fileName);
            }

            String filePath = Paths.get(terminalPath, fileName).toString();
            String stpFileName = String.format("%s.other.stp", filesModelDto.getId());

            String targetPath = Paths.get(stpterminalPath, stpFileName).toString();

            log.warn("fileType={}", fileType);

            // 2.1 调用3D建模器
            log.info("convert4NewOther {} {}", filePath, targetPath);
            int result = ConverterUtils.convert4NewOther(filePath, targetPath);
            log.warn("result={}", result);
            if (result != 0) {
                log.info("建模失败,orderNo={},boardName={}", processBoardRespiteDto.getOrderNo(),processBoardRespiteDto.getPlateName());
                processBoardRespiteDto.setStatus(3);
                processApi.setStatus(processBoardRespiteDto);
                return ResultHelper.error("建模失败，modelId=" + filesModelDto.getId());
            }

            //3.上传建模文件
            resultBO = ResultHelper.error();
            if(useOss){//上传TuoDocument2文件
                sendOssResult(targetPath, resultBO);
            }else{
                sendResult(targetPath, resultBO);
            }
            if (!resultBO.isSuccess()) {
                log.info("上传建模文件失败,orderNo={},boardName={}", processBoardRespiteDto.getOrderNo(),processBoardRespiteDto.getPlateName());
                processBoardRespiteDto.setStatus(3);
                processApi.setStatus(processBoardRespiteDto);
                return ResultHelper.error("上传建模文件，modelId=" + filesModelDto.getId());
            }
            processBoardRespiteDto.setStatus(2);
            processApi.setStatus(processBoardRespiteDto);
            log.info("{},完成任务，当前线程名={}", processBoardRespiteDto.getOrderNo(), Thread.currentThread().getName());
            return resultBO;
        } catch (Exception exception) {
            log.error("orderNo=" + processBoardRespiteDto.getOrderNo() + ",执行转换任务出错。", exception);
            processBoardRespiteDto.setStatus(3);
            processApi.setStatus(processBoardRespiteDto);
            return ResultHelper.error(exception.getMessage());
        } finally {
            // 执行回调
            callback.onComplete(processBoardRespiteDto.getOrderNo());
        }
    }

    /**
     * 上传建模文件
     *
     * @param targetPath
     * @param resultBO
     * @return
     * @throws InterruptedException
     */
    private File sendResult(String targetPath, ResultBO resultBO) throws InterruptedException {
        File stpFile = new File(targetPath);
        int count = 1;
        while (count <= 5 && !stpFile.exists()) {
            log.info("没有找到转换后的stp文件={},第{}次", targetPath, count);
            ++count;
            Thread.sleep(1000 * count + 1000);
            stpFile = new File(targetPath);
        }
        if (stpFile.exists()) {
            ResultBO result = fileStoreApi.sendResultModeling(stpFile, filesModelDto.getId(), "Modeling");
            BeanUtils.copyProperties(result, resultBO);
        }
        return stpFile;
    }

    private File sendOssResult(String targetPath, ResultBO resultBO) throws InterruptedException {
        File stpFile = new File(targetPath);
        int count = 1;
        while (count <= 5 && !stpFile.exists()) {
            log.info("没有找到转换后的stp文件={},第{}次", targetPath, count);
            ++count;
            Thread.sleep(1000 * count + 1000);
            stpFile = new File(targetPath);
        }
        if (stpFile.exists()) {
            ResultBO<Map<String,Object>> resultBO1 = fileStoreApi.getUploadUrl("modeling",stpFile.getName());
            Map<String,Object> dataMap = resultBO1.getData();
            String filePath = dataMap.get("filePath").toString();
            log.info("上传地址为："+filePath);
            boolean isSuccess = new OssUtil().uploadFile(filePath,targetPath);
            ResultBO result = ResultHelper.error("TuoDocumentBin2文件上传失败！");
            if(isSuccess){
                result = fileStoreApi.sendOssResultModeling(filesModelDto.getId(),stpFile.getName(),stpFile.length(), "Modeling");
            }
            BeanUtils.copyProperties(result, resultBO);
        }
        return stpFile;
    }

}

